package com.alawn.framework.core.web.faces.aspect;

import com.alawn.framework.core.exception.MessageResolvableException;
import com.alawn.framework.core.web.faces.annotation.MessageRequired;
import com.alawn.framework.core.web.faces.utils.RequestContextUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Configuration;

import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;

@Aspect
@Configuration
public class MessageAspect {

	@Autowired
	private MessageSource messageSource;

	private String messageCodePrefix = "";

	@Value("${myzone.faces.web.global.componentId}")
	private String componentId;

	public MessageAspect() {
		messageCodePrefix = "framework.";
		componentId = StringUtils.isNotBlank(componentId) ? componentId : "globalMessageGrowl";
	}

	public void setMessageCodePrefix(String messageCodePrefix) {
		this.messageCodePrefix = messageCodePrefix;
	}

	@Around("@annotation(messageRequired)")
	public Object showMessage(ProceedingJoinPoint joinPoint, MessageRequired messageRequired) throws Throwable {
		String title = getMessageDetail(messageCodePrefix + "tipsMessages");
		StringBuilder messageCode = new StringBuilder(messageCodePrefix);
		String messageDetail = "";

		try {
			Object result = joinPoint.proceed();
			messageCode.append(messageRequired.type().getSuccessCode());
			messageDetail = getMessageDetail(messageCode.toString(), result);
			createFacesMessage(FacesMessage.SEVERITY_INFO, title, messageDetail);

			return result;
		} catch (Exception e) {
			e.printStackTrace();
			if ((e instanceof MessageResolvableException)) {
				MessageResolvableException e1 = (MessageResolvableException) e;
				messageDetail = getMessageDetail(e1.getCategory() + "." + e1.getErrorCode(), e1.getParameters());
			} else {
				messageCode.append(messageRequired.type().getFailedCode());
				String detail = getMessageDetail(messageCodePrefix + "contactTheAdmin");
				messageDetail = getMessageDetail(messageCode.toString(), detail);
			}
			createFacesMessage(FacesMessage.SEVERITY_ERROR, title, messageDetail);

		} finally {
			if (messageRequired.growl()) {
				renderMessages();
			}
		}
		return null;
	}

	private String getMessageDetail(String messageCode, Object... detail) {
		return this.messageSource.getMessage(messageCode, detail, getResponse().getLocale());
	}

	private void createFacesMessage(Severity severity, String title, String messageDetail) {
		FacesContext context = FacesContext.getCurrentInstance();
		context.addMessage(null, new FacesMessage(severity, title, messageDetail));
	}

	private HttpServletResponse getResponse() {
		return (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
	}

	protected void renderMessages() {
		RequestContextUtils.update(componentId);
	}

}
